package org.arl.modem.transportARQ;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class PacketFactory {
	private int totalPackets;
	private int packetSize; // beta-d in paper
	private int blockSize; // m in paper
	private int padPacketCount;
	// private int totalBlocks;
	private int lastPacketId;
	private List<Packet> packets;
	private byte[] padData;

	public PacketFactory(int packetSize, int blockSize) {
		this.packetSize = packetSize;
		this.blockSize = blockSize;
	}

	/**
	 * converts the data into packets and assign the packetId and status
	 * 
	 * @param buf
	 * @return total number of packets in the buffer
	 */
	public int createPackets(byte[] buf) {

		int padPacketData = 0;
		if (buf.length % packetSize != 0) {
			padPacketData = packetSize - buf.length % packetSize;
		}
		byte[] padBytes = new byte[padPacketData];
		byte[] bufNew = new byte[buf.length + padBytes.length];

		for (int i = 0; i < bufNew.length; ++i) {
			bufNew[i] = i < buf.length ? buf[i] : padBytes[i - buf.length];
		}
		totalPackets = bufNew.length / packetSize;

		if (totalPackets % blockSize != 0) {
			padPacketCount = blockSize - totalPackets % blockSize;
		}

		byte[][] data = new byte[bufNew.length / packetSize][packetSize];
		padData = new byte[packetSize];
		packets = new LinkedList<Packet>();
		for (int i = 0; i < totalPackets; i++) {
			for (int k = 0; k < packetSize; k++) {
				// System.out.println("data part:" + buf[i * packetSize + k]);
				data[i][k] = bufNew[i * packetSize + k];
			}
			Packet p = new Packet(i, packetSize, data[i]);
			packets.add(p);
			lastPacketId = i;
		}

		return totalPackets + padPacketCount;
	}

	// /**
	// *
	// * @return the next un ACKed packet from the factory
	// */
	// public Packet getNextPacket() {
	//
	// return packets.iterator().next();
	// }

	/**
	 * Get the next block of packets
	 */
	public List<Packet> getNextBlock(int s) {
		List<Packet> pkts = new LinkedList<Packet>();
		Iterator<Packet> itr = packets.iterator();
		while (s > 0) {
			pkts.clear();
			for (int i = 0; i < this.blockSize; i++) {
				if (itr.hasNext()) {
					Packet p = itr.next();
					pkts.add(p);
					// System.out
					// .println("block contains packetid:" + p.getPacketId());
				} else {
					lastPacketId++;
					pkts.add(new Packet(lastPacketId, packetSize, padData));

				}

			}
			s--;
		}

		return pkts;
	}

	/**
	 * ACK the specified packet
	 */
	public void ackPacket(int packetId) {
		for (Packet p : packets) {
			if (p.getPacketId() == packetId) {

				packets.remove(p);
				// System.out.println("removing from list the packetid:"
				// + p.getPacketId()
				// + ":Number of remaining packets in factory:"
				// + packets.size());
				break;
			}
		}
	}

}
